/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.commons.caching;

import io.iec.edp.caf.commons.caching.proxy.JedisProxy;
import io.iec.edp.caf.commons.layeringcache.properties.CacheSetting;

import java.lang.reflect.Array;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 分布式缓存实现类
 * @author wangyandong
 */
@Deprecated
//todo 被CacheFactory依赖
public class DistributedRedisCache implements IDistributedCache,AutoCloseable {
    private JedisProxy jedisProxy;
    private String name;

    public DistributedRedisCache(String name, CacheSetting data, JedisPoolManager manager){
        this.name = name;

        this.jedisProxy = manager.getJedisProxy(data);
    }

    /**
     * 获取缓存
     * @param key 键
     * @param clazz 自定义对象的class对象
     * @param serializer 自定义序列化方式，可选的，默认为Json序列化
     * @return 缓存值
     */
    public <T> T get( String key, Class<T> clazz, ICacheSerializer serializer){
        if(serializer==null) {
            serializer = JsonSerializer.Current;
        }

        String formatKey = this.addPrefix(key);
        String data = null;
        data = jedisProxy.get(formatKey);

        return this.deserialize(data, clazz, serializer);
    }

    /**
     * 增加缓存
     * @param key 键
     * @param value 类值
     * @param options  缓存过期策略
     * @param serializer 自定义序列化格式，可选的，默认为Json序列化
     */
    public void set(String key, Object value, CacheEntryOptions options, ICacheSerializer serializer){
        //序列化为字符串
        String data = this.serialize(value,serializer);

        String formatKey = this.addPrefix(key);
        //设置缓存值
        jedisProxy.set(formatKey, data, options);
    }


    /**
     * 增加缓存
     * @param hashKey hash键
     * @param key 键
     * @param value  值
     * @param options 缓存过期策略
     * @param serializer 自定义序列化格式，可选的，默认为Json序列化
     */
    public  void hashSet(String hashKey, String key, Object value, CacheEntryOptions options , ICacheSerializer serializer){
        //序列化为字符串
        String data = this.serialize(value,serializer);

        String formatKey = this.addPrefix(hashKey);
        //设置缓存值
        jedisProxy.hset(formatKey, key, data, options);
    }

    /**
     * 获取缓存
     * @param hashKey hash键
     * @param members 字段列表
     * @param clazz 自定义对象的class对象
     * @param serializer  自定义序列化格式，可选的，默认为Json序列化
     * @return 缓存值
     */
    public <T> T[] hashMemberGet(String hashKey, String[] members,Class<T>clazz, ICacheSerializer serializer){

        String formatKey = this.addPrefix(hashKey);
        List<String> valueArr = null;
        valueArr = jedisProxy.hmget(formatKey, members);
        if(valueArr!=null){
            T[] result = (T[]) Array.newInstance(clazz, valueArr.size());
            // 循环valueArr，转换为T[]
            for (int i = 0; i < valueArr.size(); i++) {
                result[i] = this.deserialize(valueArr.get(i), clazz, serializer);
            }
            return result;
        }
        return null;
    }

    /**
     * 通过hashKey返回所有的字段
     * @param hashKey hash键
     * @return 字段
     */
    public String[] hashKeys(String hashKey){
        String formatKey = this.addPrefix(hashKey);
        Set<String> set = null;
        String[] result = null;
        //获取所有字段
        set = jedisProxy.hkeys(formatKey);
        if(set!=null) {
            //集合转为数组
            result = set.toArray(new String[set.size()]);
        }
        return result;
    }

    /**
     *返回哈希表中的所有域和值
     * @param hashKey hash键
     * @param clazz  自定义对象的class对象
     * @param serializer 自定义序列化格式，可选的，默认为Json序列化
     * @return  所有域和值
     */
    public <T> Map<String, T> hashGetAll(String hashKey, Class<T> clazz, ICacheSerializer serializer) {

        String formatKey = this.addPrefix(hashKey);
        Map<String, String> map = null;

        Map<String, T> result = new HashMap<String, T>();
        //获取所有域和值
        map = jedisProxy.hgetAll(formatKey);
        if(map!=null) {
            //循环map,对map进行序列化，转为Map<String, T>
            for (Map.Entry<String, String> entry : map.entrySet()) {
                String value = entry.getValue();
                result.put(entry.getKey(), this.deserialize(value, clazz, serializer));
            }
        }
        return result;
    }

    /**
     * 删除缓存
     * @param key 键
     */
    public void remove(String key){
        String formatKey = this.addPrefix(key);
        jedisProxy.del(formatKey);
    }
    /**
     * 删除缓存
     * @param hashKey hash键
     * @param key  键
     */
    public void hashRemove(String hashKey,String key){
        String formatKey = this.addPrefix(hashKey);
        jedisProxy.hdel(formatKey, key);
    }

    @Override
    public void close() throws Exception {
        if (this.jedisProxy != null)
            this.jedisProxy.close();
        this.jedisProxy = null;
    }

    /**
     * 将值序列化为字符串
     * @param value 待序列化的对象
     * @param serializer 序列化器
     * @return 字符串
     */
    private String serialize(Object value, ICacheSerializer serializer ){
        if(value ==null)
            return "";

        if(serializer==null){
            serializer=JsonSerializer.Current;
        }

        if(value instanceof String)
            return (String)value;
        else
            return serializer.serializeObject(value);
    }

    /**
     * 将字符串反序列化为T对象
     * @param data 数据字符串
     * @param serializer 序列化器
     * @param clazz 返回类型T
     * @return 对象
     */
    private <T> T deserialize(String data, Class<T> clazz, ICacheSerializer serializer){
        if(data ==null || "".equals(data))
            return null;

        if( clazz ==  String.class)
            return (T) data;

        if( serializer == null) {
            serializer = JsonSerializer.Current;
        }
        return serializer.deserializeObject(data,clazz);
    }

    /**
     * 为key增加前缀，避免不同功能存在重复情况
     * @param key
     * @return
     */
    private String addPrefix(String key){
        return String.format("j-%s-%s",this.name,key);
    }
}
